home *** CD-ROM | disk | FTP | other *** search
/ The Fatted Calf / The Fatted Calf.iso / Modules / BackSpaceModules / Source / Multi / MultiView.m < prev    next >
Text File  |  1992-09-09  |  14KB  |  622 lines

  1. #import "NiftyMatrix.h"
  2. #import "MultiView.h"
  3. #import <math.h>
  4.  
  5. @implementation MultiView
  6.  
  7. - initFrame:(const NXRect *)frm
  8. {
  9.     [super initFrame:frm];
  10.     sel_list = [matrix getSelectedCells:nil];
  11.     num = [sel_list count];
  12.     if (num > MAX_VIEWS) num = MAX_VIEWS;
  13.     currentLay = 0;
  14.     [self initLayouts];
  15.     return self;
  16. }
  17.  
  18. //
  19. // deal with defaults
  20. //
  21.  
  22. - readDefaults
  23. {
  24.     int i = 0, j;
  25.     char *def;
  26.     const char *tmp;
  27.     char *current;
  28.     
  29.     tmp = NXGetDefaultValue([NXApp appName],"MultiViews");
  30.     if (tmp) {
  31.         def = malloc(strlen(tmp) + 1);
  32.         strcpy (def,tmp);
  33.         while (def) {
  34.             current = rindex(def,':');
  35.             if (!current) {
  36.                 views[i] = [self viewNamed:def];
  37.                 j = [self cellNamed:def];
  38.                 [matrix setSelectionFrom:j to:j anchor:j lit:YES];
  39.                 break;
  40.             }
  41.             views[i] = [self viewNamed:(current+1)];
  42.             i++;
  43.             j = [self cellNamed:(current+1)];
  44.             [matrix setSelectionFrom:j to:j anchor:j lit:YES];
  45.             *current = '\0';
  46.         }
  47.         free(def);
  48.     }
  49.     tmp = NXGetDefaultValue([NXApp appName],"MultiLayout");
  50.     if (tmp)
  51.         currentLay = atoi(tmp);
  52.     printf("%s : %d\n",tmp,currentLay);
  53.     return self;
  54. }
  55.  
  56. - writeDefaults:sender
  57. {
  58.     int i;
  59.     const char *name;
  60.     char def[1024]; // more than we should ever need
  61.     
  62.     if (num > 0) {
  63.         def[0] = '\0';
  64.         for (i = 0; i < num; i++) {
  65.             if (i)
  66.                 strcat(def,":");
  67.             name = [[sel_list objectAt:i] stringValue];
  68.             strcat(def,name);
  69.         }
  70.         NXWriteDefault([NXApp appName], "MultiViews", def);
  71.     }
  72.     sprintf(def,"%d",currentLay);
  73.     NXWriteDefault([NXApp appName], "MultiLayout",def);
  74.     return self;
  75. }
  76.  
  77.  
  78. //
  79. // whenever we receive a newWindow message, it's a good time to
  80. // check the list and reinitialize everything
  81. // this method is called internally everytime a new selection is made
  82. - newWindow
  83. {
  84.     int i, n, lays;
  85.     int x,y,w,h;
  86.     NXRect frm;
  87.  
  88.     // clean up all of the old views.  reset their origins
  89.     NXSetRect(&frm,0,0,50,50);
  90.     for (i = 0; i < num; i++)
  91.             [[views[i] setFrame:&frm] removeFromSuperview];
  92.     
  93.     // clean up the screen... what a mess!
  94.     [self display];
  95. //    [self lockFocus];
  96. //    [self drawSelf:&frame :1];
  97. //    [self unlockFocus];
  98.     
  99.     // find out what was selected, and get the appropriate views
  100.     sel_list = [matrix getSelectedCells:nil];
  101.     num = [sel_list count];
  102.     lays = lay_defs[currentLay].num;
  103.     n = MIN(lays,num);
  104.     num = n;
  105.     for (i = 0; i < n; i++) {
  106.         views[i] = [self viewFrom:[sel_list objectAt:i]];
  107.         if (NX_X(&lay_defs[currentLay].pos[i]) == 0)
  108.             x = 0;
  109.         else
  110.             x = NX_WIDTH(&frame) / NX_X(&lay_defs[currentLay].pos[i]);
  111.         if (NX_Y(&lay_defs[currentLay].pos[i]) == 0)
  112.             y = 0;
  113.         else
  114.             y = NX_HEIGHT(&frame) / NX_Y(&lay_defs[currentLay].pos[i]);
  115.         w = NX_WIDTH(&frame) / NX_WIDTH(&lay_defs[currentLay].pos[i]);
  116.         h = NX_HEIGHT(&frame) / NX_HEIGHT(&lay_defs[currentLay].pos[i]);
  117.         NXSetRect(&frm,x,y,w,h);
  118.         [[views[i] setFrame:&frm] setClipping:YES];
  119.         [self addSubview:views[i]];
  120.         // we need to make sure that they draw themselves once first
  121.         // [views[i] lockFocus];
  122.         [views[i] display];
  123.         // [views[i] unlockFocus];
  124.     }
  125.     return self;
  126. }
  127.  
  128.  
  129. //
  130. // rather than call oneStep on every method at once,
  131. // just call it on one, then next time, call it on the next one.
  132. // for some reason, this seemed to improve performance
  133. // (I'm not sure why though)
  134. //
  135. - oneStep
  136. {
  137.     static int cur = 0;
  138.     [views[cur] lockFocus];
  139.     // this is necessary for some views (such as Space) to function properly
  140.     if ([views[cur] respondsTo:@selector(didLockFocus)])
  141.         [views[cur] didLockFocus];
  142.     [views[cur] oneStep];
  143.     [views[cur] unlockFocus];
  144.     cur++;
  145.     if (cur >= num) 
  146.         cur = 0;
  147.     return self;
  148. }
  149.  
  150.  
  151. //
  152. // when this is called, we know that we've just been loaded up
  153. // so we take advantage of that fact and do a lot of initialization
  154. //
  155. - inspector:sender
  156. {
  157.   char buf[MAXPATHLEN];
  158.   NXRect frm, scrollRect;
  159.   NXSize matSize, cellSize;
  160.   
  161.   thinker = sender;
  162.   pub = (struct thinkerDef *)thinker;
  163.   modList = pub->moduleList;
  164.   if (!inspectorPanel)
  165.     {
  166.       // 
  167.       // Time to make the matrix... time to make the matrix
  168.       //
  169.       sprintf(buf,"%s/Multi.nib",(char *)[sender moduleDirectory:"Multi"]);
  170.       [NXApp loadNibFile:buf owner:self withNames:NO];
  171.       [scrollView getFrame:&frm];
  172.       matrix = [[NiftyMatrix alloc] initFrame:&frm
  173.                                       mode:NX_LISTMODE
  174.                                     cellClass:[Cell class]
  175.                                     numRows:0
  176.                                     numCols:1];
  177.       [self fillMatrix];
  178.       [scrollView getFrame:&scrollRect];
  179.       [ScrollView getContentSize:&matSize
  180.                        forFrameSize:&scrollRect.size
  181.                     horizScroller:NO
  182.                     vertScroller:YES
  183.                     borderType:NX_BEZEL];
  184.       [matrix getCellSize:&cellSize];
  185.       cellSize.width = matSize.width;
  186.       [matrix setCellSize:&cellSize];
  187.       [matrix sizeToCells];
  188.       [matrix setAutosizeCells:YES];
  189.       [matrix setAutoscroll:YES];
  190.       [scrollView setDocView:matrix];
  191.       [[matrix superview] setAutoresizeSubviews:YES];
  192.       [matrix setAutosizing:NX_WIDTHSIZABLE];
  193.       [matrix setTarget:self];
  194.       [matrix setAction:@selector(select:)];
  195.       [matrix setDoubleAction:@selector(inspect:)];
  196.       [self readDefaults];
  197.       //
  198.       // time to make the funky layout thingie
  199.       //
  200.     // yuck... there must be a better way to initialize arrays like this
  201.     layouts[0] = lay1;
  202.     layouts[1] = lay2;
  203.     layouts[2] = lay3;
  204.     layouts[3] = lay4;
  205.     layouts[4] = lay5;
  206.     layouts[5] = lay6;
  207.     layouts[6] = lay7;
  208.     layouts[7] = lay8;
  209.     layouts[8] = lay9;
  210.     layouts[9] = lay10;
  211.     layouts[10] = lay11;
  212.  
  213.     [layouts[currentLay] getFrame:&frm];
  214.     NXSetRect(&frm,0,0,NX_WIDTH(&frm),NX_HEIGHT(&frm));
  215.     [layouts[currentLay] setFrame:&frm];
  216.     [[layout addSubview:layouts[currentLay]] display];
  217.     }
  218.   return inspectorPanel;
  219. }
  220.  
  221.  
  222. //
  223. // clean up the "multi inspector"
  224. //
  225. - inspectorWillBeRemoved
  226. {
  227.     int i;
  228.     NXRect foo;
  229.     NXSetRect(&foo,0,0,0,0);
  230.     for (i = 0; i < num; i++)
  231.             [views[i] setFrame:&foo];
  232.     if (otherInspector)
  233.         [otherInspector close];
  234.     return self;
  235. }
  236.  
  237. - setImage:image
  238. {
  239.     int i;
  240.     for (i = 0; i < num; i++)
  241.         if ([views[i] respondsTo:@selector(setImage:)])
  242.             [views[i] setImage:image];
  243.     return self;
  244. }
  245.  
  246. //
  247. // helper function to -fillMatrix
  248. //
  249. - addCellWithString:(const char *)str at:(int)row
  250. {
  251.     id theCell;
  252.     
  253.     [matrix insertRowAt:row];
  254.     theCell = [matrix cellAt:row :0];
  255.     [theCell setStringValue:str];
  256.     return self;
  257. }
  258.  
  259. //
  260. // fill the matrix with the view names
  261. ///
  262. - fillMatrix
  263. {
  264.   int i, n, j;
  265.  
  266.   n = [modList count];
  267.   for (i = j = 0; i < n; i++)
  268.     {
  269.         if (strcmp([modList nameAt: i], "Multi"))
  270. #ifdef MULTI_LOCALIZED
  271.             [self addCellWithString:NXLocalString([modList nameAt: i], 0, 0)
  272. #else
  273.             [self addCellWithString:[modList nameAt:i]
  274. #endif                            
  275.                         at:(j++)];
  276.     }
  277.   return self;
  278. }
  279.  
  280. //
  281. // called whenever an item in the matrix is clicked on
  282. //
  283. - select:sender
  284. {
  285.     [self newWindow];
  286.     [[self window] flushWindow];
  287.     return self;
  288. }
  289.  
  290.  
  291. //
  292. // funky layout selection interface code
  293. //
  294.  
  295. - layoutUp:sender
  296. {
  297.     NXRect frm;
  298.     [layouts[currentLay] removeFromSuperview];
  299.     currentLay --;
  300.     if (currentLay < 0)
  301.         currentLay = 10;
  302.     [layouts[currentLay] getFrame:&frm];
  303.     NXSetRect(&frm,0,0,NX_WIDTH(&frm),NX_HEIGHT(&frm));
  304.     [layouts[currentLay] setFrame:&frm];
  305.     [[layout addSubview:layouts[currentLay]] display];
  306.     [self newWindow];
  307.     [[self window] flushWindow];
  308.     return self;
  309. }
  310.  
  311. - layoutDown:sender
  312. {
  313.     NXRect frm;
  314.     [layouts[currentLay] removeFromSuperview];
  315.     currentLay ++;
  316.     if (currentLay > 10)
  317.         currentLay = 0;
  318.     [layouts[currentLay] getFrame:&frm];
  319.     NXSetRect(&frm,0,0,NX_WIDTH(&frm),NX_HEIGHT(&frm));
  320.     [layouts[currentLay] setFrame:&frm];
  321.     [[layout addSubview:layouts[currentLay]] display];
  322.     [self newWindow];
  323.     [[self window] flushWindow];
  324.     return self;
  325. }
  326.  
  327. //
  328. // initialize all of the layout definitions.
  329. // this is ugly because it's all hardcoded.  If I ever mess with the
  330. // layouts in the interface, I'll also have to change this.  Unfortunately,
  331. // I didn't see a straightforward way of doing it automatically from the drawn
  332. // layouts.  Maybe I should do it the other way, and draw the layouts by hand.
  333. // that probably makes sense if I ever do any future development on this
  334. //
  335. - initLayouts
  336. {
  337.     lay_defs[0].num = 1;
  338.     [self allocLayout:0];
  339.     NXSetRect(&lay_defs[0].pos[0],0,0,1,1);
  340.     lay_defs[1].num = 2;
  341.     [self allocLayout:1];
  342.     NXSetRect(&lay_defs[1].pos[0],0,2,1,2);
  343.     NXSetRect(&lay_defs[1].pos[1],0,0,1,2);
  344.     lay_defs[2].num = 2;
  345.     [self allocLayout:2];
  346.     NXSetRect(&lay_defs[2].pos[0],0,0,2,1);
  347.     NXSetRect(&lay_defs[2].pos[1],2,0,2,1);
  348.     lay_defs[3].num = 3;
  349.     [self allocLayout:3];
  350.     NXSetRect(&lay_defs[3].pos[0],0,0,2,1);
  351.     NXSetRect(&lay_defs[3].pos[1],2,2,2,2);
  352.     NXSetRect(&lay_defs[3].pos[2],2,0,2,2);
  353.     lay_defs[4].num = 3;
  354.     [self allocLayout:4];
  355.     NXSetRect(&lay_defs[4].pos[0],0,0,2,2);
  356.     NXSetRect(&lay_defs[4].pos[1],0,2,2,2);
  357.     NXSetRect(&lay_defs[4].pos[2],2,0,2,1);
  358.     lay_defs[5].num = 3;
  359.     [self allocLayout:5];
  360.     NXSetRect(&lay_defs[5].pos[0],0,2,1,2);
  361.     NXSetRect(&lay_defs[5].pos[1],0,0,2,2);
  362.     NXSetRect(&lay_defs[5].pos[2],2,0,2,2);
  363.     lay_defs[6].num = 3;
  364.     [self allocLayout:6];
  365.     NXSetRect(&lay_defs[6].pos[0],0,0,1,2);
  366.     NXSetRect(&lay_defs[6].pos[1],0,2,2,2);
  367.     NXSetRect(&lay_defs[6].pos[2],2,2,2,2);
  368.     lay_defs[7].num = 4;
  369.     [self allocLayout:7];
  370.     NXSetRect(&lay_defs[7].pos[0],0,0,2,2);
  371.     NXSetRect(&lay_defs[7].pos[1],2,2,2,2);
  372.     NXSetRect(&lay_defs[7].pos[2],0,2,2,2);
  373.     NXSetRect(&lay_defs[7].pos[3],2,0,2,2);
  374.     lay_defs[8].num = 6;
  375.     [self allocLayout:8];
  376.     NXSetRect(&lay_defs[8].pos[0],0,0,2,3);
  377.     NXSetRect(&lay_defs[8].pos[1],2,0,2,3);
  378.     NXSetRect(&lay_defs[8].pos[2],0,3,2,3);
  379.     NXSetRect(&lay_defs[8].pos[3],2,3,2,3);
  380.     NXSetRect(&lay_defs[8].pos[4],0,1.5,2,3);
  381.     NXSetRect(&lay_defs[8].pos[5],2,1.5,2,3);
  382.     lay_defs[9].num = 6;
  383.     [self allocLayout:9];
  384.     NXSetRect(&lay_defs[9].pos[0],0,0,3,2);
  385.     NXSetRect(&lay_defs[9].pos[1],3,0,3,2);
  386.     NXSetRect(&lay_defs[9].pos[2],1.5,0,3,2);
  387.     NXSetRect(&lay_defs[9].pos[3],0,2,3,2);
  388.     NXSetRect(&lay_defs[9].pos[4],3,2,3,2);
  389.     NXSetRect(&lay_defs[9].pos[5],1.5,2,3,2);
  390.     lay_defs[10].num = 9;
  391.     [self allocLayout:10];
  392.     NXSetRect(&lay_defs[10].pos[0],0,0,3,3);
  393.     NXSetRect(&lay_defs[10].pos[1],3,3,3,3);
  394.     NXSetRect(&lay_defs[10].pos[2],1.5,1.5,3,3);
  395.     NXSetRect(&lay_defs[10].pos[3],0,3,3,3);
  396.     NXSetRect(&lay_defs[10].pos[4],3,0,3,3);
  397.     NXSetRect(&lay_defs[10].pos[5],0,1.5,3,3);
  398.     NXSetRect(&lay_defs[10].pos[6],1.5,0,3,3);
  399.     NXSetRect(&lay_defs[10].pos[7],3,1.5,3,3);
  400.     NXSetRect(&lay_defs[10].pos[8],1.5,3,3,3);
  401.     return self;
  402. }
  403.  
  404. - allocLayout:(int)index
  405. {
  406.     int n;
  407.     n = lay_defs[index].num;
  408.     lay_defs[index].pos = malloc(sizeof(NXRect) * n);
  409.     return self;
  410. }
  411.  
  412. //
  413. // BackSpace Thinker emulation code
  414. //
  415.  
  416.  
  417. - performMethodOnViews:(SEL)sel
  418. {
  419.     int i;
  420.     for (i = 0; i < num; i++)
  421.         if ([views[i] respondsTo:sel])
  422.             [views[i] perform:sel];
  423.     return self;
  424. }
  425.  
  426. - enteredScreenSaverMode
  427. {
  428.     [self performMethodOnViews:@selector(enteredScreenSaverMode)];
  429.     return self;
  430. }
  431.  
  432. - willExitScreenSaverMode
  433. {
  434.     [self performMethodOnViews:@selector(willExitScreenSaverMode)];
  435.     return self;
  436. }
  437.  
  438. - inspect:sender
  439. {
  440.     id insp = nil;
  441.     NXRect frm;
  442.     
  443.     if ([[self viewFrom:sender] respondsTo:@selector(inspector:)])
  444.         insp = [[self viewFrom:sender] inspector:thinker];
  445.     if (insp == nil)
  446.         insp = [thinker nullInspector];
  447.     [insp getFrame:&frm];
  448.     [otherInspector setContentView:insp];
  449.     [otherInspector makeKeyAndOrderFront:self];
  450.     [otherInspector sizeWindow:NX_WIDTH(&frm) :NX_HEIGHT(&frm)];
  451.     [[otherInspector contentView] display];
  452.     return self;
  453. }
  454.  
  455.  
  456. //
  457. // these methods walk the list of views to match names and cells with
  458. // the views that go with them
  459. //
  460.  
  461. - viewFrom:sender
  462. {
  463.     const char *name;
  464.     int i, n;
  465.     id view = nil;
  466.     
  467.     name = [sender stringValue];
  468.     n = [modList count];
  469.     for (i = 0; i < n; i++)
  470.         if (!strcmp([modList nameAt: i], name))
  471.             view = [modList viewAt: i];
  472.     if (view == nil)
  473.         view = [self loadView:name];
  474.     if (view == nil)
  475.         fprintf(stderr,"returned nil: %s\n",name);
  476.     return view;
  477. }
  478.  
  479. - viewNamed:(const char *)name
  480. {
  481.     int i, n;
  482.     id view = nil;
  483.     
  484.     n = [modList count];
  485.     for (i = 0; i < n; i++)
  486.         if (!strcmp([modList nameAt: i], name))
  487.             view = [modList viewAt: i];
  488.     if (!view)
  489.         view = [self loadView:name];
  490.     return view;
  491. }
  492.  
  493. - objectNamed:(const char *)name
  494. {
  495.     int i, n;
  496.     n = [modList count];
  497.     for (i = 0; i < n; i++)
  498.         if (!strcmp([modList nameAt: i], name))
  499.             return [modList objectAt: i];
  500.     return nil;
  501. }
  502.  
  503. - (int)cellNamed:(const char *)name
  504. {
  505.     int i, n;
  506.  
  507.     n = [matrix cellCount];
  508.     for (i = 0; i < n; i++)
  509.         if (!strcmp([[matrix cellAt: i :0] stringValue], name))
  510.             return i;
  511.     return -1;
  512. }
  513.  
  514. // this is pretty much a duplicate of - backView from ThinkMore.m
  515. // I couldn't just call that directly because it relies on its own state
  516. // to know what view to load
  517. - loadView:(const char *)name
  518. {
  519.     NXRect aFrame = {{0,0},{200,200}};
  520.     id theView = nil;
  521.     char path[MAXPATHLEN];
  522.     id myClass;
  523.     char *filenames[] = {path, NULL};
  524.     ModuleInfo *mp;
  525.     struct mach_header *header;
  526.  
  527.     //if (index(name,' '))
  528.     //    name = strip_spaces(name);
  529.     mp = [self objectNamed:name];
  530.     if ([mp path]) {
  531.         long ret;
  532.         while (1)
  533.         {
  534.             sprintf(path, "%s/%sView.BackO", [mp path], name);
  535.             ret = objc_loadModules(filenames, NULL, NULL, &header, NULL);
  536.             if (ret && [mp respondsTo:@selector(useNextPath)])
  537.                 if ([mp useNextPath])
  538.                     continue;
  539.             break;
  540.         }
  541.         if (ret)
  542.         {
  543.             NXRunAlertPanel([NXApp appName], NXLocalString("Could not dynamically load class: %sView",0,0),
  544.                 NULL, NULL, NULL, name);
  545.             return nil;
  546.         }
  547.         else
  548.         {
  549.             [mp setHeader:header];
  550.         }
  551.         //at this point we must have a valid name for a loaded class
  552.     }    
  553.     sprintf(path,"%sView", name);
  554.     myClass = objc_getClass(path);
  555.  
  556.     // heh... god I love @defs! :-)
  557.     theView = [[myClass allocFromZone:pub->backZone] initFrame:&aFrame];
  558.     [mp setView:theView];
  559.     // fake 'em out by passing thinker instead of self
  560.     if ([theView respondsTo:@selector(inspector:)])
  561.         [theView inspector:thinker];
  562.  
  563.     return theView;
  564. }
  565.  
  566. - drawSelf:(const NXRect *)frm :(int)count
  567. {
  568.     PSsetgray(0.0);
  569.     NXRectFillList(frm,count);
  570.     return self;
  571. }
  572.  
  573. - (BOOL)useBufferedWindow
  574. {
  575.   return YES;
  576. }
  577.  
  578. - (const char *)windowTitle
  579. {
  580.   return "MultiView";
  581. }
  582.  
  583. - sizeTo:(NXCoord)width :(NXCoord)height
  584. {
  585.     [super sizeTo:width :height];
  586.     [self newWindow];
  587.     return self;
  588. }
  589.  
  590. //
  591. // handoff methods... these all just call the equivalent in Thinker
  592. // some of the modules depend on them
  593. //
  594.  
  595. - commonImageInspector
  596. {
  597.     return [thinker commonImageInspector];
  598. }
  599.  
  600. - nullInspector
  601. {
  602.     return [thinker nullInspector];
  603. }
  604.  
  605. - spaceInspector
  606. {
  607.     return [thinker spaceInspector];
  608. }
  609.  
  610. - boinkInspector
  611. {
  612.     return [thinker boinkInspector];
  613. }
  614.  
  615. - (const char *)moduleDirectory:(const char *)name
  616. {
  617.     return [thinker moduleDirectory:name];
  618. }
  619.  
  620.  
  621. @end
  622.